﻿/*
 * UdpReliableConnection.h
 */
#ifndef __GDK_UDPRELIABLECONNECTION_H__
#define __GDK_UDPRELIABLECONNECTION_H__

#include <gdk/core/Memory.h>
#include <gdk/core/MemoryBlock.h>
#include <gdk/core/MemoryStream.h>
#include <gdk/net/Socket.h>
#include <gdk/net/UdpConnection.h>
#include <set>


#define UDP_PACKAGES_COUNT	16
#define UDP_SEQUENCE_MASK	0x7f



namespace gdk
{


////////////////////////////////////////
class GDK_NET_EXPORT UdpReliableConnection : public UdpConnection
{
	DECLARE_CLASS_HANDLE(UdpReliableConnection)
	DECLARE_CLASS_INSTANCE(UdpReliableConnection)


public:
	class Package : virtual public Unknown
	{
		DECLARE_CLASS_HANDLE(Package)
		DECLARE_CLASS_INSTANCE(Package)

	public:
		enum
		{
			PACKAGE_MAX_LOST_PACKAGE= UDP_PACKAGES_COUNT, /*丢失的数据*/
			PACKAGE_HEAD_SIZE		= sizeof(uint8_t) * 2 + sizeof(uint16_t) + PACKAGE_MAX_LOST_PACKAGE, /*数据包头大小*/
			PACKAGE_MAX_DATA_SIZE	= UdpConnection::PACKAGE_MAX_DATA_SIZE - PACKAGE_HEAD_SIZE, /*包最大数据*/
			PACKAGE_SIZE			= PACKAGE_HEAD_SIZE + PACKAGE_MAX_DATA_SIZE, /*整个数据包大小*/
		};

	public:

#if defined(_WIN32)
#		pragma pack(push, 1)
#endif
		struct
		{
#ifdef __LITTLE_ENDIAN__
			uint8_t		_dummy:1;
			uint8_t		_sequence:7;
#else //__BIG_ENDIAN__
			uint8_t		_sequence:7;
			uint8_t		_dummy:1;
#endif

			uint8_t		_echo;

/*
			uint16_t	_dataLen:11;
			uint16_t	_immediatelyEcho:1;
			uint16_t	_sequence2:4;
*/
#define	PACKAGE_DATA_LENGTH_MASK		0xffe0
#define	PACKAGE_DATA_LENGTH_OFFSET		5
#define	PACKAGE_IMMEDIATELYECHO_MASK	0x0010
#define	PACKAGE_SEQUENCE2_MASK			0x000f
			uint16_t	_reserved;

			uint8_t		_lostpkg[PACKAGE_MAX_LOST_PACKAGE];
			uint8_t		_buffer[PACKAGE_MAX_DATA_SIZE];
		}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
		__attribute__((packed))
#endif
					_data;
#if defined(_WIN32)
#		pragma pack(pop)
#endif

	private:
		__INLINE__ Package(void)
		{
			//**********************************
			/*
			_data._dummy	=0;
			_data._sequence	=0;
			_data._echo		=0;
			_data._reserved	=0;
			*/
			//----------------------------------
			(*(int32_t*)&_data) = 0;
			//**********************************
		}

	private:
		__INLINE__ void setData(uint16_t n, int mask, int offset)
		{
			_data._reserved = hton(uint16_t((ntoh(_data._reserved) & ~mask) | ((n << offset) & mask)));
		}
		__INLINE__ uint16_t getData(int mask, int offset) const
		{
			return uint16_t((ntoh(_data._reserved) & mask) >> offset);
		}
	public:
		__INLINE__ void setDataSize(uint16_t n)
		{
			setData(n, PACKAGE_DATA_LENGTH_MASK, PACKAGE_DATA_LENGTH_OFFSET);
		}
		__INLINE__ uint16_t getDataSize(void) const
		{
			return getData(PACKAGE_DATA_LENGTH_MASK, PACKAGE_DATA_LENGTH_OFFSET);
		}
		__INLINE__ void setImmediatelyEcho(bool b)
		{
			setData((b ? PACKAGE_IMMEDIATELYECHO_MASK : 0), PACKAGE_IMMEDIATELYECHO_MASK, 0);
		}
		__INLINE__ bool isImmediatelyEcho(void) const
		{
			return getData(PACKAGE_IMMEDIATELYECHO_MASK, 0) != 0;
		}
		__INLINE__ void setSequence2(uint8_t n)
		{
			setData(n, PACKAGE_SEQUENCE2_MASK, 0);
		}
		__INLINE__ uint8_t getSequence2(void) const
		{
			return static_cast<uint8_t>(getData(PACKAGE_SEQUENCE2_MASK, 0));
		}
		__INLINE__ uint16_t getPackageSize(void) const
		{
			return static_cast<uint16_t>(getDataSize() + PACKAGE_HEAD_SIZE);
		}
		__INLINE__ bool checkDataSize(void) const
		{
			return getDataSize() <= PACKAGE_MAX_DATA_SIZE;
		}

	private:
		friend class UdpReliableConnection;
	};

private:
	typedef Package::Handle						Package_Handle;
	typedef std::map<uint8_t, Package_Handle>	PackageMap;


	uint8_t					_curSendSequence:7;
	PackageMap				_sendPackages;
	MemoryStream::Handle	_hSendBuffer;

	uint8_t					_curRecvSequence:7;
	PackageMap				_recvPackages;
	MemoryStream::Handle	_hRecvBuffer;

	uint8_t					_curSendSequence2:4;
	uint8_t					_curRecvSequence2:4;

	std::set<uint8_t>		_lostPackages; //丢失的数据包(需要主机重新发送)
	std::set<uint8_t>		_resendPackages; //需要重新发送到的数据包

	bool					_recvDataEcho;
	uint8_t					_curSequenceEcho:7;
	bool					_immediatelyEcho;
	uint32_t				_timeSinceLastEcho;
	bool					_echoFlag;
	bool					_resetLostPackages;
	uint8_t					_recvLastSequence:7; //最后接收的数据包


protected:
	UdpReliableConnection(void);

private:
	void cleanSendPackages(void);
	void resetLostPackages(void);
	bool send(Package *pkg);

public:
	virtual void onTick(uint32_t timeSinceLastTick);
	virtual ssize_t available(void) const;
	virtual ssize_t receive(void *buf, ssize_t len);
	virtual ssize_t send(const void *data, ssize_t len);
	virtual void close(void);

protected:
	virtual void onReceive(void);
};




}//namespace gdk


#endif //__GDK_UDPRELIABLECONNECTION_H__
